// Kony


#include "Player/BasePlayerController.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "BaseGameplayTags.h"
#include "EnhancedInputSubsystems.h"  // 解决UEnhancedInputLocalPlayerSubsystem声明问题[6,10](@ref)
#include "NavigationPath.h"
#include "NavigationSystem.h"
#include "NiagaraFunctionLibrary.h"
#include "ShaderPrintParameters.h"
#include "AbilitySystem/BaseAbilitySystemComponent.h"
#include "Actor/BaseMagicCircle.h"
#include "Components/DecalComponent.h"
#include "Components/SplineComponent.h"
#include "Input/BaseInputComponent.h"
#include "Interaction/EnemyInterface.h"
#include "Interaction/CombatInterface.h"
#include "Interaction/PlayerInterface.h"
#include "GameFramework/Character.h"
#include "GASC_HuanLing/GASC_HuanLing.h"
#include "Interaction/TargetInterface.h"
#include "UI/Widget/DamageTextComponent.h"

//基础玩家控制器类
ABasePlayerController::ABasePlayerController()
{
	bReplicates = true;
	
	//设置左键移动部分
	//创建样条组件
	Spline = CreateDefaultSubobject<USplineComponent>("Spline");
	
}

//Tick函数 就是一分钟执行60次 每一次算1针的函数
void ABasePlayerController::PlayerTick(float DeltaTime)
{
	Super::PlayerTick(DeltaTime);
	CursorTrace();
	AutoRun();
	UpdateMagicCircleLocation(); //更新魔法阵
	
}
//显示 魔法阵函数
void ABasePlayerController::ShowMagicCircle(UMaterialInstance* DecalMaterial, FGameplayTag SpellInputTag)
{
	if (!IsValid(MagicCircle))
	{
		//如果当前没有魔法阵就生成魔法阵
		MagicCircle = GetWorld()->SpawnActor<ABaseMagicCircle>(MagicCircleClass);
		//如果传入了贴花材质 则设置贴花材质
		if (DecalMaterial)
		{
			MagicCircle->MagicCircleDecal->SetMaterial(0,DecalMaterial);
		}
	}
	bShowMouseCursor = false;
	//设置法阵状态
	bMagicCircleActive = true;
	CurrentSpellInputTag = SpellInputTag;
	bMagicCircleJustCast = true;
}
//隐藏 魔法阵函数
void ABasePlayerController::HideMagicCircle()
{
	if (IsValid(MagicCircle))
	{
		//已有魔法阵就销毁
		MagicCircle->Destroy();
	}
	bShowMouseCursor = true;
	CurrentSpellInputTag = FGameplayTag();
	
	FTimerHandle TimerHandle;
	GetWorld()->GetTimerManager().SetTimer(
		TimerHandle,
		[this]()
		{
			bMagicCircleJustCast = false;
		},
		0.1f,
		false
	);
}

//RPC 在目标位置伤害显示函数 如果是服务端就服务端显示 如果是客户端就客户端显示
void ABasePlayerController::ShowDamageNumber_Implementation(float DamageAmount, ACharacter* TargetCharacter, bool bBlockedHit, bool bCriticalHit)
{
	//IsLocalController 增加这个是为了判断如果是本地控制器 才显示伤害文本 避免伤害显示到服务器
	if (IsValid(TargetCharacter) && DamageTextComponentClass && IsLocalController())
	{
		//创建伤害显示组件
		UDamageTextComponent* DamageText = NewObject<UDamageTextComponent>(TargetCharacter,DamageTextComponentClass);
		//并注册组件
		DamageText->RegisterComponent();
		//获取目标跟组件 并将伤害组件附加到其跟组件上
		DamageText->AttachToComponent(TargetCharacter->GetRootComponent(),FAttachmentTransformRules::KeepRelativeTransform);
		//然后分离其根组件，这个是为了让伤害数字不一直跟着，看效果决定是否使用
		DamageText->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
		//传入伤害值
		DamageText->SetDamageText(DamageAmount, bBlockedHit, bCriticalHit);
	}
}

//点击左键 自动移动到目标位置函数
void ABasePlayerController::AutoRun()
{
	if (!bAutoRunning) return;
	if (APawn* ControlledPawn = GetPawn<APawn>())
	{
		//这个变量表示 样条线上最接近角色棋子的位置
		const FVector LocationOnSpline = Spline->FindLocationClosestToWorldLocation(ControlledPawn->GetActorLocation(),ESplineCoordinateSpace::World);
		//获取棋子对应方向
		const FVector Direction = Spline->FindDirectionClosestToWorldLocation(LocationOnSpline,ESplineCoordinateSpace::World);
		
		// 8方向标准化：将方向向量标准化到8个固定方向
		const FVector NormalizedDirection = NormalizeTo8Directions(Direction);
		
		//设置移动 传入标准化后的方向参数
		ControlledPawn->AddMovementInput(NormalizedDirection);
		//检查与目的地的距离
		const float DistanceToDestination = (LocationOnSpline-CachedDestination).Length();
		//如果角色和目标距离小于 设定的最小距离 则停止自动移动
		if (DistanceToDestination<=AutoRunAcceptanceRadius)
		{
			bAutoRunning = false;
		}
	}
}

// 8方向标准化函数：将任意方向向量标准化到8个固定方向
FVector ABasePlayerController::NormalizeTo8Directions(const FVector& Direction)
{
	FVector NormalizedDirection = Direction;
	
	// 如果方向向量长度大于阈值，则进行8方向标准化
	if (NormalizedDirection.Size() > 0.1f)
	{
		// 计算方向向量的角度（弧度）
		float Angle = FMath::Atan2(NormalizedDirection.Y, NormalizedDirection.X);
		
		// 将角度转换为度数
		float AngleDegrees = FMath::RadiansToDegrees(Angle);
		
		// 标准化到8个方向（每45度一个方向）
		// 将角度调整到0-360度范围
		if (AngleDegrees < 0) AngleDegrees += 360.0f;
		
		// 计算最接近的8方向角度
		float SnapAngle = FMath::RoundToFloat(AngleDegrees / 45.0f) * 45.0f;
		
		// 将角度转换回弧度
		float SnapAngleRadians = FMath::DegreesToRadians(SnapAngle);
		
		// 重新计算标准化的方向向量
		NormalizedDirection.X = FMath::Cos(SnapAngleRadians);
		NormalizedDirection.Y = FMath::Sin(SnapAngleRadians);
		NormalizedDirection.Z = 0.0f; // 保持Z轴为0
	}
	
	return NormalizedDirection;
}
//更新魔法阵位置
void ABasePlayerController::UpdateMagicCircleLocation()
{
	if (IsValid(MagicCircle))
	{
		//更新魔法阵位置为鼠标位置
		MagicCircle->SetActorLocation(CursorHit.ImpactPoint);
	}
}

//鼠标追踪
void ABasePlayerController::CursorTrace()
{
	
	//如果有匹配的禁用光标的标签 则取消目标标记直接返回
	// if (GetASC() && GetASC()->HasMatchingGameplayTag(FBaseGameplayTags::Get().Player_Block_CursorTrace))
	// {
	// 	//解除所有高亮
	// 	UnHighlightActor(LastActor);
	// 	UnHighlightActor(ThisActor);
	// 	LastActor = nullptr;
	// 	ThisActor = nullptr;
	// 	return;
	// }
	//判断如果是在法阵状态下，设置忽略玩家角色通道，其他情况默认鼠标通道
	const ECollisionChannel TraceChannel = IsValid(MagicCircle) ? ECC_ExcludePlayers : ECC_Visibility; 
	GetHitResultUnderCursor(TraceChannel, false, CursorHit);
	//如果光标没有命中任何物体 返回
	if (!CursorHit.bBlockingHit) return;

	LastActor = ThisActor;
	//检查选中的目标是否有效，并检查是否实现了目标接口
	if (IsValid(CursorHit.GetActor()) && CursorHit.GetActor()->Implements<UTargetInterface>())
	{
		ThisActor =	CursorHit.GetActor(); //如果使用 TScriptInterface 就不用转换，如果这个无法用就要使用下面得转换接口类型
	}
	else
	{
		ThisActor = nullptr;
	}
	/**
	 * * 判断光标是否移动到敌人的多种判断
	 * A.LastActor is null && ThisActor is null
	 *    - Do nothing 没选中敌人
	 * B.LastActor is null && ThisActor is valid
	 *    - Highlight ThisActor 移动到敌人身上 设置高亮
	 * C.LastActor is valid && ThisActor is null
	 *    - Unhighlight LastActor 移开取消高亮
	 * D.Both actors are valid,but LastActor != ThisActor
	 *    - 如果是敌人之间的切换 去掉上一个高亮，设置新敌人高亮
	 * E.Both actors are valid,and are the same actor
	 *    - 鼠标停留在上一次选中的敌人没有移动，那么 Do nothing
	 * **/
	if (LastActor != ThisActor)
	{
		UnHighlightActor(LastActor); //解除旧目标高亮
		HighlightActor(ThisActor); //高亮当前目标
	}
}
//显示Actor高亮
void ABasePlayerController::HighlightActor(AActor* InActor)
{
	if (IsValid(InActor) && InActor->Implements<UTargetInterface>())
	{
		if (InActor) ITargetInterface::Execute_HighlightActor(InActor);
	}
}
//解除Actor高亮
void ABasePlayerController::UnHighlightActor(AActor* InActor)
{
	if (IsValid(InActor) && InActor->Implements<UTargetInterface>())
	{
		if (InActor) ITargetInterface::Execute_UnHighlightActor(InActor);
	}
}
//判断鼠标选中的目标函数
ETargetingStatus ABasePlayerController::DetermineTargetingStatus(AActor* InActor)
{
	if (IsValid(InActor))
	{
		return ThisActor->Implements<UEnemyInterface>() ? ETargetingStatus::TargetingEnemy : 
		   ThisActor->Implements<UPlayerInterface>() ? ETargetingStatus::TargetingPlayer : 
		   ETargetingStatus::TargetingObject;
	}
	else
	{
		return ETargetingStatus::NotTargeting;
	}
}

//按下按键 处理函数,调用能力系统组件里的同名函数
void ABasePlayerController::AbilityInputTagPressed(FGameplayTag InputTag)
{
	//判断是否是左键 如果是则进入移动处理
	if (InputTag.MatchesTagExact(FBaseGameplayTags::Get().InputTag_LMB))
	{
		//判断鼠标当前瞄准的是什么目标
		TargetingStatus = DetermineTargetingStatus(ThisActor);
		if (IsValid(ThisActor)) bAutoRunning = false;
	}
	if (GetASC() == nullptr) return;
	//法阵状态下的输入重定向
	if (bMagicCircleActive)
	{
		//如果是左键，转发给当前技能
		if (InputTag.MatchesTagExact(FBaseGameplayTags::Get().InputTag_LMB))
		{
			if (GetASC() && CurrentSpellInputTag.IsValid())
			{
				GetASC()->AbilityInputTagPressed(CurrentSpellInputTag);
			}
			return;
		}
	}
	//如果有匹配的禁用按下标签 则返回
	if (GetASC() && GetASC()->HasMatchingGameplayTag(FBaseGameplayTags::Get().Player_Block_InputPressed)) return;
	GetASC()->AbilityInputTagPressed(InputTag);
	// //打印日志
	// GEngine->AddOnScreenDebugMessage(1,3.f,FColor::Red,*InputTag.ToString());
}
//松开按键 处理函数,调用能力系统组件里的同名函数
void ABasePlayerController::AbilityInputTagReleased(FGameplayTag InputTag)
{
	if (GetASC() == nullptr) return;
	
	//判断如果是法阵状态，点击左键松开时直接返回不进行后续 避免移动
	if (bMagicCircleJustCast && InputTag.MatchesTagExact(FBaseGameplayTags::Get().InputTag_LMB)) return;
	//如果有匹配的禁用松开标签 则返回
	if (GetASC() && GetASC()->HasMatchingGameplayTag(FBaseGameplayTags::Get().Player_Block_InputPressed)) return;
	//判断如果不是左键则执行能力
	if (!InputTag.MatchesTagExact(FBaseGameplayTags::Get().InputTag_LMB))
	{
		if (GetASC()) GetASC()->AbilityInputTagReleased(InputTag);
		return;
	}
	if (GetASC()) GetASC()->AbilityInputTagReleased(InputTag);
	
	//左键松开时的目标选择逻辑
	if (CursorHit.bBlockingHit && CursorHit.GetActor())
	{
		AActor* HitActor = CursorHit.GetActor();
		//检查是否实现了CombatInterface
		if (HitActor->Implements<UCombatInterface>())
		{
			//设置选中目标到玩家接口
			if (APawn* ControlledPawn = GetPawn<APawn>())
			{
				if (ControlledPawn->Implements<UPlayerInterface>())
				{
					IPlayerInterface::Execute_SetSelectedTarget(ControlledPawn, HitActor);
				}
			}
		}
	}
	
	//如果是左键，并且目标是敌人 则执行能力
	if (TargetingStatus != ETargetingStatus::TargetingEnemy && !bShiftKeyDown)
	{
		//目标不是敌人则移动
		//获取受控制的角色棋子
		const APawn* ControlledPawn = GetPawn<APawn>();
		/* 这里是自动导航移动部分 UNavigationPath */
		//判断如果单击释放 要设置导航路径
		if (FollowTime <= ShortPressThreshold && ControlledPawn)
		{
			//判断点击的目标是否有 目标接口
			if (IsValid(ThisActor) && ThisActor->Implements<UTargetInterface>())
			{
				//把点击的物体指定目标位置 替换移动目的地
				ITargetInterface::Execute_SetMoveToLocation(ThisActor, CachedDestination);
			}
			else if (GetASC() && !GetASC()->HasMatchingGameplayTag(FBaseGameplayTags::Get().Player_Block_CursorTrace))
			{
				//如果没有替换目的地时 才显示点击地面光标效果
				//点击移动地面 显示光标 ，点击光标效果 在没有禁用光标追踪时显示
				UNiagaraFunctionLibrary::SpawnSystemAtLocation(this,ClickNiagaraSystem,CachedDestination);
			}
			//获取导航路径 世界对象,起点，终点
			if (UNavigationPath* NavPath = UNavigationSystemV1::FindPathToLocationSynchronously(this,ControlledPawn->GetActorLocation(),CachedDestination))
			{
				//清理样条
				Spline->ClearSplinePoints();
				//遍历路径点
				for (const FVector& PointLoc : NavPath->PathPoints)
				{
					//添加样条点
					Spline->AddSplinePoint(PointLoc,ESplineCoordinateSpace::World);
					//绘制调试球体
					// DrawDebugSphere(GetWorld(),PointLoc,8.f,8,FColor::Green,false,5.f);
				}
				//获取最后一个路径点，用于点击非跟踪系统内的地方时候 他会不停跑的问题
				//教学写法 CachedDestination = NavPath->PathPoints[NavPath->PathPoints.Num()-1];
				if (NavPath->PathPoints.Num() > 0)
				{
					CachedDestination = NavPath->PathPoints.Last();
					bAutoRunning = true;
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("NavPath->PathPoints is empty!"));
				}
			}
		}
		//恢复各变量默认值
        FollowTime = 0.f;
		TargetingStatus = ETargetingStatus::NotTargeting;//设置目标为无目标
	}
	
	//打印日志
	// GEngine->AddOnScreenDebugMessage(2,3.f,FColor::Blue,*InputTag.ToString());
}
//按住按键 处理函数,调用能力系统组件里的同名函数
void ABasePlayerController::AbilityInputTagHeld(FGameplayTag InputTag)
{
	if (GetASC() == nullptr) return;
	//判断如果是法阵状态，点击左键松开时直接返回不进行后续 避免移动
	if (bMagicCircleJustCast && InputTag.MatchesTagExact(FBaseGameplayTags::Get().InputTag_LMB)) return;
	//如果有匹配的禁用保持标签 则返回
	if (GetASC() && GetASC()->HasMatchingGameplayTag(FBaseGameplayTags::Get().Player_Block_InputHeld)) return;
	//判断如果不是左键则执行能力
	if (!InputTag.MatchesTagExact(FBaseGameplayTags::Get().InputTag_LMB))
	{
		if (GetASC()) GetASC()->AbilityInputTagHeld(InputTag);
		return;
	}
	//如果是左键，并且目标是敌人 则执行能力 或 如果按下SHIFT强制释放技能
	if (TargetingStatus == ETargetingStatus::TargetingEnemy || bShiftKeyDown)
	{
		if (GetASC()) GetASC()->AbilityInputTagHeld(InputTag);
	}
	else
	{
		//目标不是敌人则移动
		//获取游戏时间 计算移动了多少秒
		FollowTime += GetWorld()->DeltaTimeSeconds;
		if (CursorHit.bBlockingHit)
		{
			//缓存命中点的向量
			CachedDestination = CursorHit.ImpactPoint;
		}
		//获取控制角色棋子
		if (APawn* ControlledPawn = GetPawn<APawn>())
		{
			//获取世界方向
			const FVector WorldDirection = (CachedDestination - ControlledPawn->GetActorLocation()).GetSafeNormal();
			
			// 8方向标准化：将世界方向向量标准化到8个固定方向
			const FVector NormalizedWorldDirection = NormalizeTo8Directions(WorldDirection);
			
			ControlledPawn->AddMovementInput(NormalizedWorldDirection);
		}
	}
	//打印日志
	// GEngine->AddOnScreenDebugMessage(3,3.f,FColor::Green,*InputTag.ToString());
}

UBaseAbilitySystemComponent* ABasePlayerController::GetASC()
{
	//持久化 能力系统组件
	if (BaseAbilitySystemComponent == nullptr)
	{
		BaseAbilitySystemComponent = Cast<UBaseAbilitySystemComponent>(UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetPawn<APawn>()));
	}
	return BaseAbilitySystemComponent;
}

void ABasePlayerController::BeginPlay()
{
	Super::BeginPlay();
	//验证是否设置了玩家控制器
	check(PlayerInputContext);

	UEnhancedInputLocalPlayerSubsystem* Subsystem =  ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
	//如果子系统存在
	if (Subsystem)
	{
		// check(Subsystem);
		Subsystem->AddMappingContext(PlayerInputContext,0);//如果多个输入，设置优先级0为最高级
	}
	bShowMouseCursor = true;//显示鼠标
	DefaultMouseCursor = EMouseCursor::Default;//鼠标样式
	//设置鼠标模式
	FInputModeGameAndUI InputModeData;
	InputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock); //设置鼠标是否锁定
	InputModeData.SetHideCursorDuringCapture(false); //设置鼠标是否隐藏
	SetInputMode(InputModeData);
	
	
}
//设置输入组件
void ABasePlayerController::SetupInputComponent()
{
	Super::SetupInputComponent(); //调用父类方法
	// //创建一个输入组件
	// UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(InputComponent);
	// //绑定移动动作
	// EnhancedInputComponent->BindAction(MoveAction,ETriggerEvent::Triggered,this,&ABasePlayerController::Move);
	//创建一个输入组件
	UBaseInputComponent* BaseInputComponent = CastChecked<UBaseInputComponent>(InputComponent);
	//绑定移动动作
	BaseInputComponent->BindAction(MoveAction,ETriggerEvent::Triggered,this,&ABasePlayerController::Move);
	//绑定shift按下 强制释放技能
	BaseInputComponent->BindAction(ShiftAction,ETriggerEvent::Started,this,&ABasePlayerController::ShiftPressed);
	BaseInputComponent->BindAction(ShiftAction,ETriggerEvent::Completed,this,&ABasePlayerController::ShiftReleased);
	
	//添加安全检查，确保InputConfig正确配置
	if (!InputConfig)
	{
		UE_LOG(LogTemp, Error, TEXT("InputConfig is not set in BasePlayerController Blueprint! Please set it in the Blueprint."));
		return;
	}
	
	if (InputConfig->AbilityInputActions.Num() == 0)
	{
		UE_LOG(LogTemp, Warning, TEXT("InputConfig AbilityInputActions array is empty! No ability inputs will be bound."));
		return;
	}
	
	//绑定自定义增强输入
	BaseInputComponent->BindAbilityActions(InputConfig,this,&ThisClass::AbilityInputTagPressed,&ThisClass::AbilityInputTagReleased, &ThisClass::AbilityInputTagHeld);

}
//移动函数
void ABasePlayerController::Move(const FInputActionValue& InputActionValue)
{
	//如果有匹配的禁用保持标签 则返回
	if (GetASC() && GetASC()->HasMatchingGameplayTag(FBaseGameplayTags::Get().Player_Block_InputPressed)) return;
	//获取2D XY向量
	const FVector2D InputAxisVector = InputActionValue.Get<FVector2D>();
	const FRotator Rotation = GetControlRotation();//获取当前控制器旋转
	const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);//获取当前控制器Y轴旋转

	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);//获取当前控制器X轴方向 前
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);//获取当前控制器Y轴方向 右

	if (APawn* ControlledPawn = GetPawn<APawn>()){
		ControlledPawn->AddMovementInput(ForwardDirection, InputAxisVector.Y);//添加X轴方向移动
		ControlledPawn->AddMovementInput(RightDirection, InputAxisVector.X);//添加Y轴方向移动
	}
}


